package ua.com.minus1.lookbattle.net;

import android.app.Activity;
import android.content.Context;
import android.util.Log;
import com.google.gson.Gson;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

import java.io.*;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * Created by IntelliJ IDEA.
 * User: Flash
 * Date: 22.05.12
 * Time: 13:11
 * To change this template use File | Settings | File Templates.
 */
public class HttpManager {

    public static final String USE_CACHE = "useCache";
    private ExecutorService executorService;
    private Context mContext;
    private HttpFileCache fileCache;
    private HttpMemoryCache memoryCache;
    private static final int HTTP_TIMEOUT = 30 * 1000;

    public HttpManager(Context context) {
        fileCache = new HttpFileCache(context);
        init(context);
    }

    public HttpManager(Context context, String cacheFolder) {
        fileCache = new HttpFileCache(context, cacheFolder);
        init(context);
    }

    private void init(Context context) {
        memoryCache = new HttpMemoryCache<Object>();
        mContext = context;
    }

    private ExecutorService getExecutorService() {
        if(executorService == null)
            executorService = Executors.newFixedThreadPool(5);
        return executorService;
    }

    public <T> Future loadClass(String url, Class<T> type, HttpResultHandler<T> resultHandler, String param) {
        boolean useCache = param.equals(USE_CACHE);
        if (useCache) {
            Object cachedResult = memoryCache.get(url);
            if (cachedResult != null) {
                resultHandler.onResultLoadComplete((T) cachedResult);
                return null;
            }
        }
        return getExecutorService().submit(new InputStreamLoader(mContext, type, resultHandler, url, useCache));
    }
    
    public <T> Future loadClass(String url, Class<T> type, HttpResultHandler<T> resultHandler) {
        return getExecutorService().submit(new InputStreamLoader(mContext, type, resultHandler, url, false));
    }

    private InputStream getInputStream(HttpGet httpGet, boolean useCache) {
        InputStream inputStream;

        File f = null;
        if (useCache) {
            f = fileCache.getFile(httpGet.getURI().toString());
            try {
                inputStream = new FileInputStream(f);
                Log.i(HttpManager.class.getName(), "get input stream from file");
                return inputStream;
            } catch (FileNotFoundException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }
        }


        //client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, PROXY_HOST);
        try {
            HttpClient client = new DefaultHttpClient();
            final HttpParams params = client.getParams();
            HttpConnectionParams.setConnectionTimeout(params, HTTP_TIMEOUT);
            ConnManagerParams.setTimeout(params, HTTP_TIMEOUT);
            HttpResponse response = client.execute(httpGet);
            StatusLine statusLine = response.getStatusLine();
            int statusCode = statusLine.getStatusCode();
            if (statusCode == 200) {
                HttpEntity entity = response.getEntity();
                inputStream = entity.getContent();
                if (useCache) {
                    OutputStream outputStream = new FileOutputStream(f);
                    Utils.copyStream(inputStream, outputStream);
                    outputStream.close();
                    return new FileInputStream(f);
                } else
                    return inputStream;
            } else {
                Log.e(HttpManager.class.toString(), "Failed to download file");
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public File getCacheFile(String url) {
        return fileCache.getFile(url);
    }

    public void clearCache() {
        memoryCache.clear();
        fileCache.clear();
    }

    public static String getParamsString(String... params){
        List<NameValuePair> paramsList = new LinkedList<NameValuePair>();
        for (int i = 0; i < params.length - 1; i = i + 2) {
            paramsList.add(new BasicNameValuePair(params[i], params[i + 1]));
        }
        String paramsString = URLEncodedUtils.format(paramsList, "utf-8");
        return paramsString;
    }

    class InputStreamLoader implements Runnable{

        private HttpResultHandler resultHandler;
        private String url;
        private Context context;
        private boolean useCache;
        private Class type;

        public InputStreamLoader(Context context, Class type, HttpResultHandler resultHandler, String url, boolean useCache) {
            this.type = type;
            this.resultHandler = resultHandler;
            this.url = url;
            this.context = context;
            this.useCache = useCache;
        }

        public void run() {
            InputStream inputStream = getInputStream(new HttpGet(url), useCache);
            InputStreamReader streamReader = new InputStreamReader(inputStream);

            if(Thread.currentThread().isInterrupted())
                return;

            Gson gson = new Gson();
            final Object result = gson.fromJson(streamReader, type);
            if(!useCache)
                memoryCache.put(url, result);


            if(Thread.currentThread().isInterrupted())
                return;

            ((Activity) context).runOnUiThread(new Runnable() {
                public void run() {
                    resultHandler.onResultLoadComplete(result);
                }
            });
        }

    }

    public interface HttpResultHandler<T>{
        void onResultLoadComplete(T result);
    }
}
